package org.zavgame.rest;

import java.util.Properties;
import java.util.Random;

import javax.naming.InitialContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import org.apache.log4j.Logger;
import org.zavgame.ejb.PlayerInterface;
import org.zavgame.ejb.PlayerRequest;
import org.zavgame.ejb.PlayerResponse;

/**
 * RESTful Coins service to play the game.
 * 
 * @author alexey
 *
 */
@Path("coins")
public class CoinsService
{

   private static final Logger LOG = Logger.getLogger(CoinsService.class.getName());

   private static final String PLAYERS_REMOTE_INTERFACE = "PlayersRemote";

   private static final int DEFAULT_PAYMENT = 1500;

   private static final int DEFAULT_BALANCE_CHANGE = 50;

   /**
    * InitialContext instance for the remote EJB interface.
    */
   @javax.inject.Inject
   private CoinsInitialContext coinsInitialContext;

   /**
    * Play the game.
    * User try to guess the coin side.
    * 
    * @param coinSide
    * @return
    */
   @GET
   @Produces("application/json")
   public Game play(@QueryParam("coinSide") Integer coinSide)
   {
      LOG.info("coinSide=" + coinSide);
      if (coinSide == null)
         throw new IllegalArgumentException("coinSide parameter is null");

      try
      {
         String username = "John";
         String transactionId = "1";

         PlayerInterface players = (PlayerInterface)coinsInitialContext.getContext().lookup(PLAYERS_REMOTE_INTERFACE);
         int balanceChange = 0;
         int randomCoinSide = new Random().nextInt(2);
         if (coinSide.intValue() == randomCoinSide)
         {
            balanceChange = DEFAULT_BALANCE_CHANGE;
         }
         else
         {
            balanceChange = -DEFAULT_BALANCE_CHANGE;
         }

         PlayerRequest playerRequest = new PlayerRequest(username, transactionId, balanceChange);
         PlayerResponse playerWallet = players.balanceUpdate(playerRequest);

         Game game =
            new Game(playerRequest.getUsername(), playerWallet.getBalanceVersion(),
               playerWallet.getBalanceAfterChange(), randomCoinSide);
         return game;

      }
      catch (Throwable t)
      {
         throw new WebApplicationException(t, createErrorResponse(500, t));
      }
   }

   /**
    * User pay the money.
    * 
    * @param uriInfo
    * @return
    */
   @Path("payment")
   @GET
   @Produces("application/json")
   public Response payment(@Context UriInfo uriInfo)
   {
      try
      {
         String username = "John";
         String transactionId = "1";

         PlayerInterface players = (PlayerInterface)coinsInitialContext.getContext().lookup(PLAYERS_REMOTE_INTERFACE);
         PlayerResponse playerWallet =
            players.balanceUpdate(new PlayerRequest(username, transactionId, DEFAULT_PAYMENT));
         return Response.ok(Integer.toString(playerWallet.getBalanceAfterChange())).type(MediaType.APPLICATION_JSON)
            .status(200).build();
      }
      catch (Throwable t)
      {
         throw new WebApplicationException(t, createErrorResponse(500, t));
      }
   }

   /**
    * Get the user balance.
    * 
    * @param uriInfo
    * @return
    */
   @Path("balance")
   @GET
   @Produces("application/json")
   public Response balance(@Context UriInfo uriInfo)
   {
      try
      {
         String username = "John";
         String transactionId = "1";

         PlayerInterface players = (PlayerInterface)coinsInitialContext.getContext().lookup(PLAYERS_REMOTE_INTERFACE);
         PlayerRequest playerRequest = new PlayerRequest(username, transactionId, 0);
         PlayerResponse playerWallet = players.getBalance(playerRequest);
         int balance = 0;
         if (playerWallet != null && playerWallet.getErrorCode() == 200)
         {
            balance = playerWallet.getBalanceAfterChange();
         }
         return Response.ok(Integer.toString(balance)).type(MediaType.APPLICATION_JSON).status(200).build();
      }
      catch (Throwable t)
      {
         throw new WebApplicationException(t, createErrorResponse(500, t));
      }
   }

   /**
    * It is a demo resource to show on how can we change the InitialContext instance.
    * 
    * @param httpRequest
    * @return
    */
   @Path("initialcontext")
   @GET
   @Produces("application/json")
   public Response setInitialContext(@Context HttpServletRequest httpRequest)
   {
      try
      {
         // to get parameters from the request, we can use the code like:
         // httpRequest.getParameter("java.naming.factory.initial");
         // Below is the demo InitialContext initialized
         Properties p = new Properties();
         p.put("java.naming.factory.initial", "org.apache.openejb.client.RemoteInitialContextFactory");
         // it is the same url as configured
         p.put("java.naming.provider.url", "ejbd://localhost:4201");
         // user and pass optional
         p.put("java.naming.security.principal", "daniel");
         p.put("java.naming.security.credentials", "password");

         coinsInitialContext.setContext(new InitialContext(p));

         PlayerInterface players = (PlayerInterface)coinsInitialContext.getContext().lookup(PLAYERS_REMOTE_INTERFACE);
         return Response.ok("ok").type(MediaType.APPLICATION_JSON).status(200).build();
      }
      catch (Throwable t)
      {
         throw new WebApplicationException(t, createErrorResponse(500, t));
      }
   }

   /**
    * On debug purpose, return the stack trace in the response markup.
    * 
    * @param status
    * @param t
    * @return
    */
   private Response createErrorResponse(int status, Throwable t)
   {
      return Response.status(status).entity(ExceptionUtils.stacktraceToString(t)).type(MediaType.APPLICATION_JSON).build();
   }

}
